package com.taobao.taokeeper.monitor.task.job;

import static com.taobao.common.toolkit.constant.StringConstant.EMPTY_STRING;
import static com.taobao.common.toolkit.constant.SymbolConstant.COLON;
import static com.taobao.common.toolkit.constant.SymbolConstant.PERCENT;
import static com.taobao.common.toolkit.constant.SymbolConstant.SLASH;
import static com.taobao.taokeeper.common.constant.SystemConstant.MINS_RATE_OF_COLLECT_HOST_PERFORMANCE;
import static com.taobao.taokeeper.common.constant.SystemConstant.passwordOfSSH;
import static com.taobao.taokeeper.common.constant.SystemConstant.userNameOfSSH;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

import com.taobao.common.toolkit.entity.HostPerformanceEntity;
import com.taobao.common.toolkit.exception.DaoException;
import com.taobao.common.toolkit.exception.SSHException;
import com.taobao.common.toolkit.util.SSHUtil;
import com.taobao.common.toolkit.util.StringUtil;
import com.taobao.taokeeper.common.GlobalInstance;
import com.taobao.taokeeper.dao.AlarmSettingsDAO;
import com.taobao.taokeeper.dao.ZooKeeperClusterDAO;
import com.taobao.taokeeper.message.impl.TbMessageSender;
import com.taobao.taokeeper.model.AlarmSettings;
import com.taobao.taokeeper.model.ZooKeeperCluster;
import com.taobao.taokeeper.model.type.Message;
import com.taobao.taokeeper.monitor.core.ThreadPoolManager;

/**
 * Description: Collect info of host performance
 * @author yinshi.nc
 * @Date 2011-10-28
 */
public class HostPerformanceCollectJob implements Runnable {

	private static final Logger LOG = LoggerFactory.getLogger( HostPerformanceCollectJob.class );

	@Override
	public void run() {

		while ( true ) {
			try {
				// 根据clusterId来获取一个zk集群
				WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
				ZooKeeperClusterDAO zooKeeperClusterDAO = ( ZooKeeperClusterDAO ) wac.getBean( "zooKeeperClusterDAO" );
				AlarmSettingsDAO alarmSettingsDAO = ( AlarmSettingsDAO ) wac.getBean( "alarmSettingsDAO" );
				try {
					List< ZooKeeperCluster > zooKeeperClusterSet = null;
					Map< Integer, ZooKeeperCluster > zooKeeperClusterMap = GlobalInstance.getAllZooKeeperCluster();
					if ( null == zooKeeperClusterMap ) {
						zooKeeperClusterSet = zooKeeperClusterDAO.getAllDetailZooKeeperCluster();
					} else {
						zooKeeperClusterSet = new ArrayList< ZooKeeperCluster >();
						zooKeeperClusterSet.addAll( zooKeeperClusterMap.values() );
					}

					if ( null == zooKeeperClusterSet || zooKeeperClusterSet.isEmpty() ) {
						LOG.warn( "No zookeeper cluster config" );
					} else {
						for ( ZooKeeperCluster zookeeperCluster : zooKeeperClusterSet ) { // 对每个cluster处理
							if ( null != zookeeperCluster && null != zookeeperCluster.getServerList() ) {
								AlarmSettings alarmSettings = alarmSettingsDAO.getAlarmSettingsByCulsterId( zookeeperCluster.getClusterId() );
								for ( String server : zookeeperCluster.getServerList() ) {
									server = StringUtil.trimToEmpty( server );
									if ( StringUtil.isBlank( server ) )
										continue;
									String ip = StringUtil.trimToEmpty( server.split( COLON )[0] );
									try {
										HostPerformanceEntity hostPerformanceEntity = SSHUtil.getHostPerformance( ip, userNameOfSSH, passwordOfSSH );
										sendAlarm( alarmSettings, hostPerformanceEntity, zookeeperCluster.getClusterName() );
										GlobalInstance.putHostPerformanceEntity( ip, hostPerformanceEntity );
										LOG.info( "HostPerformanceEntity collect of #" + zookeeperCluster.getClusterName() + "-" + ip + " ："
												+ hostPerformanceEntity );
									} catch ( SSHException e ) {
										LOG.warn( "HostPerformanceEntity collect of " + ip + " ：" + e.getMessage() );
									} catch ( Throwable exception ) {
										LOG.error( "程序出错: " + exception.getMessage() );
										exception.printStackTrace();
									}
								}// for each server
							}// for each cluster
						}
					}
					LOG.info( "Finish all cluster HostPerformanceEntity collect" );
					GlobalInstance.timeOfUpdateHostPerformanceSet = StringUtil.convertDate2String( new Date() );
				} catch ( DaoException daoException ) {
					LOG.warn( "Error when handle data base" + daoException.getMessage() );
				} catch ( Exception e ) {
					LOG.error( "程序出错：" + e.getMessage() );
					e.printStackTrace();
				}
				// 每2分钟收集一次检测
				Thread.sleep( 1000 * 60 * MINS_RATE_OF_COLLECT_HOST_PERFORMANCE );
			} catch ( Throwable e ) {
				LOG.error( "Error when HostPerformanceEntityCollectJob" + e.getMessage() );
				e.printStackTrace();
			}
		}
	}

	/**
	 * 检查是否需要进行报警
	 */
	public void sendAlarm( AlarmSettings alarmSettings, HostPerformanceEntity hostPerformanceEntity, String clusterName ) {

		if ( null == alarmSettings )
			return;

		String wangwangList = alarmSettings.getWangwangList();
		String phoneList = alarmSettings.getPhoneList();

		String maxCpuUsage = alarmSettings.getMaxCpuUsage();
		String maxMemoryUsage = alarmSettings.getMaxMemoryUsage();
		String maxLoad = alarmSettings.getMaxLoad();

		String dataDir = alarmSettings.getDataDir();
		String dataLogDir = alarmSettings.getDataLogDir();
		String maxDiskUsage = alarmSettings.getMaxDiskUsage();

		if ( !StringUtil.isBlank( maxCpuUsage ) ) { // 需要进行cpu报警
			String cpuUsage = hostPerformanceEntity.getCpuUsage();
			if ( !StringUtil.isBlank( cpuUsage ) && cpuUsage.endsWith( "%" ) ) {
				cpuUsage = cpuUsage.replaceAll( "%", "" );
				double difference = Double.parseDouble( cpuUsage ) - Double.parseDouble( maxCpuUsage );
				if ( 0 < difference ) {
					LOG.warn( "ZooKeeper所在机器cpu负载已经很高：" + cpuUsage + "-" + maxCpuUsage + "=" + difference );
					// 报警
					if ( GlobalInstance.needAlarm.get() ) {
						ThreadPoolManager.addJobToMessageSendExecutor( new TbMessageSender( new Message( wangwangList, "ZooKeeper所在机器cpu负载超过阀值-"
								+ clusterName, hostPerformanceEntity.getIp() + "的CPU负载过高：" + cpuUsage + "-" + maxCpuUsage + "=" + difference,
								Message.MessageType.WANGWANG ) ) );
						ThreadPoolManager.addJobToMessageSendExecutor( new TbMessageSender( new Message( phoneList, "ZooKeeper所在机器cpu负载超过阀值-"
								+ clusterName, "ZooKeeper所在机器cpu负载超过阀值-" + clusterName + hostPerformanceEntity.getIp() + "的CPU负载过高：" + cpuUsage + "-"
								+ maxCpuUsage + "=" + difference, Message.MessageType.WANGWANG ) ) );
					}
				}
			}
		}

		if ( !StringUtil.isBlank( maxMemoryUsage ) ) { // 需要进行 memory 报警
			String memoryUsage = hostPerformanceEntity.getMemoryUsage();
			if ( !StringUtil.isBlank( memoryUsage ) && memoryUsage.endsWith( "%" ) ) {
				memoryUsage = memoryUsage.replaceAll( "%", "" );
				double difference = Double.parseDouble( memoryUsage ) - Double.parseDouble( maxMemoryUsage );
				if ( 0 < difference ) {
					LOG.warn( "ZooKeeper所在机器Memory负载已经很高：" + memoryUsage + "-" + maxMemoryUsage + "=" + difference );
					// 报警
					if ( GlobalInstance.needAlarm.get() ) {
						ThreadPoolManager.addJobToMessageSendExecutor( new TbMessageSender( new Message( wangwangList, "ZooKeeper所在机器内存负载超过阀值-"
								+ clusterName, hostPerformanceEntity.getIp() + "的内存负载过高：" + memoryUsage + "-" + maxMemoryUsage + "=" + difference,
								Message.MessageType.WANGWANG ) ) );
						ThreadPoolManager.addJobToMessageSendExecutor( new TbMessageSender( new Message( phoneList, "ZooKeeper所在机器内存负载超过阀值-"
								+ clusterName, "ZooKeeper所在机器内存负载超过阀值-" + clusterName + hostPerformanceEntity.getIp() + "的内存负载过高：" + memoryUsage
								+ "-" + maxMemoryUsage + "=" + difference, Message.MessageType.SMS ) ) );
					}
				}
			}
		}

		if ( !StringUtil.isBlank( maxLoad ) ) { // 需要进行 load 报警
			String load = hostPerformanceEntity.getLoad();
			if ( !StringUtil.isBlank( load ) ) {
				double difference = Double.parseDouble( load ) - Double.parseDouble( maxLoad );
				if ( 0 < difference ) {
					LOG.warn( "ZooKeeper所在机器Load负载已经很高：" + load + "-" + maxLoad + "=" + difference );
					if ( GlobalInstance.needAlarm.get() ) {
						ThreadPoolManager.addJobToMessageSendExecutor( new TbMessageSender( new Message( wangwangList, "ZooKeeper所在机器Load负载超过阀值-"
								+ clusterName, hostPerformanceEntity.getIp() + "的Load负载过高：" + load + "-" + maxLoad + "=" + difference,
								Message.MessageType.WANGWANG ) ) );
						ThreadPoolManager.addJobToMessageSendExecutor( new TbMessageSender( new Message( phoneList, "ZooKeeper所在机器Load负载超过阀值-"
								+ clusterName, "ZooKeeper所在机器Load负载超过阀值-" + clusterName + hostPerformanceEntity.getIp() + "的Load负载过高：" + load + "-"
								+ maxLoad + "=" + difference, Message.MessageType.SMS ) ) );
					}
				}
			}
		}

		try {
			if ( !StringUtil.isBlank( dataDir ) || !StringUtil.isBlank( dataLogDir ) ) { // 需要进行
																							// disk容量
																							// 报警

				dataDir = StringUtil.trimToEmpty( dataDir );
				dataLogDir = StringUtil.trimToEmpty( dataLogDir );

				if ( !StringUtil.isBlank( maxDiskUsage ) ) {

					Map< String, String > diskUsageMap = hostPerformanceEntity.getDiskUsageMap();
					if ( null != diskUsageMap ) {
						for ( String mountedOn : diskUsageMap.keySet() ) {

							if ( StringUtil.trimToEmpty( mountedOn ).equalsIgnoreCase( SLASH ) )
								continue;

							if ( dataDir.startsWith( StringUtil.trimToEmpty( mountedOn ) )
									|| dataLogDir.startsWith( StringUtil.trimToEmpty( mountedOn ) ) ) {
								int diskUsage = Integer.parseInt( StringUtil.trimToEmpty( diskUsageMap.get( mountedOn ) ).replace( PERCENT,
										EMPTY_STRING ) );
								if ( diskUsage > Integer.parseInt( maxDiskUsage ) ) {
									LOG.warn( "ZooKeeper所在机器" + hostPerformanceEntity.getIp() + "磁盘使用量较大 " + mountedOn + ", 使用率达到" + diskUsage
											+ "%, 超过设置的阈值: " + maxDiskUsage + "%" );
									if ( GlobalInstance.needAlarm.get() ) {
										ThreadPoolManager.addJobToMessageSendExecutor( new TbMessageSender( new Message( wangwangList,
												"ZooKeeper所在机器磁盘使用量较大-" + clusterName, "ZooKeeper所在机器" + hostPerformanceEntity.getIp() + "磁盘使用量较大 "
														+ mountedOn + ", 使用率达到" + diskUsage + "%, 超过设置的阈值: " + maxDiskUsage + "%",
												Message.MessageType.WANGWANG ) ) );
										ThreadPoolManager.addJobToMessageSendExecutor( new TbMessageSender( new Message( phoneList,
												"ZooKeeper所在机器磁盘使用量较大-" + clusterName, "ZooKeeper所在机器磁盘使用量较大-" + clusterName
														+ hostPerformanceEntity.getIp() + "磁盘使用量较大 " + mountedOn + ", 使用率达到" + diskUsage
														+ "%, 超过设置的阈值: " + maxDiskUsage + "%", Message.MessageType.SMS ) ) );
									}
								}
							}
						}
					}
				}

			}
		} catch ( Exception e ) {
			LOG.error( "进行disk容量报警出错：" + e.getMessage() );
			e.printStackTrace();
		}// disk 容量报警

	}

	public static void main( String[] args ) {
		Thread thread = new Thread( new HostPerformanceCollectJob() );
		thread.start();
	}
}
